package com.ruoyi.ai.factory.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.dashscope.common.Role;
import com.ruoyi.ai.domain.vo.WxChatVo;
import com.ruoyi.ai.domain.vo.WxModelConfigVo;
import com.ruoyi.ai.enums.MfgEnum;
import com.ruoyi.ai.enums.SparkModelEnum;
import com.ruoyi.ai.factory.ModelChatTemplate;
import com.ruoyi.ai.ws.ChatWebSocketManager;
import com.ruoyi.common.exception.ServiceException;
import com.unfbx.sparkdesk.SparkDeskClient;
import com.unfbx.sparkdesk.entity.*;
import com.unfbx.sparkdesk.listener.ChatListener;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

/**
 * 讯飞星火实现
 */
@Slf4j
@Service
public class XfSparkModelChatService extends ModelChatTemplate {
    @Resource
    private ChatWebSocketManager chatWebSocketManager;

    public XfSparkModelChatService() {
        super(MfgEnum.XF_SPARK.getType());
    }

    @Override
    public String chatStream(List<WxChatVo> chatVoList, Long userId) {
        try {
            log.info("发送的请求为{}", chatVoList);
            // 同步信号量
            Semaphore semaphore = new Semaphore(0);
            // 结果拼接对象
            StringBuilder resultBuilder = new StringBuilder();
            SparkDeskClient sparkDeskClient = getSparkDeskClient();
            AIChatRequest aiChatRequest = getAIChatRequestBase();
            InPayload inPayload = buildPayload(chatVoList);
            aiChatRequest.setPayload(inPayload);

            //发送请求
            sparkDeskClient.chat(new ChatListener(aiChatRequest) {
                //异常回调
                @SneakyThrows
                @Override
                public void onChatError(AIChatResponse aiChatResponse) {
                    log.error("调用异常:{}", aiChatResponse);
                }

                //输出回调
                @Override
                public void onChatOutput(AIChatResponse aiChatResponse) {
                    String newMessage = aiChatResponse.getPayload().getChoices().getText().get(0).getContent();
                    StringBuilder finalResBuilder = resultBuilder.append(newMessage);
                    //据说代码块不终止
                    // 通过websocket返回给前端
                    //chatWebSocketManager.sendOneMessage(userId, finalResBuilder.toString());
                    chatWebSocketManager.sendOneMessage(userId, newMessage);
                }

                //会话结束回调
                @Override
                public void onChatEnd() {
                    semaphore.release();
                }

                //会话结束 获取token使用信息回调
                @Override
                public void onChatToken(Usage usage) {
                }
            });
            semaphore.acquire();
            //发送对话结束标记，前端好判断本次对话已结束，允许下一轮对话
            chatWebSocketManager.sendOneMessage(userId, OVER_FLAG);
            //将最终结果返回
            return resultBuilder.toString();
        } catch (Exception e) {
            log.error("调用讯飞接口出现问题：{}", e.getMessage());
            throw new ServiceException("调用讯飞接口出现问题");
        }
    }

    @Override
    public String chatStreamOnce(String content) {
        try {
            log.info("发送的请求为{}", content);
            // 同步信号量
            Semaphore semaphore = new Semaphore(0);
            // 结果拼接对象
            StringBuilder resultBuilder = new StringBuilder();
            SparkDeskClient sparkDeskClient = getSparkDeskClient();
            AIChatRequest aiChatRequest = getAIChatRequestBase();

            List<WxChatVo> chatVoList = new ArrayList<>();
            WxChatVo wxChatVo = new WxChatVo();
            wxChatVo.setRole(Role.USER.getValue());
            wxChatVo.setContent(content);
            chatVoList.add(wxChatVo);

            InPayload inPayload = buildPayload(chatVoList);
            aiChatRequest.setPayload(inPayload);

            //发送请求
            sparkDeskClient.chat(new ChatListener(aiChatRequest) {
                //异常回调
                @SneakyThrows
                @Override
                public void onChatError(AIChatResponse aiChatResponse) {
                    log.error("调用异常:{}", aiChatResponse);
                }

                //输出回调
                @Override
                public void onChatOutput(AIChatResponse aiChatResponse) {
                    String newMessage = aiChatResponse.getPayload().getChoices().getText().get(0).getContent();
                    StringBuilder finalResBuilder = resultBuilder.append(newMessage);
                }

                //会话结束回调
                @Override
                public void onChatEnd() {
                    semaphore.release();
                }

                //会话结束 获取token使用信息回调
                @Override
                public void onChatToken(Usage usage) {
                }
            });
            semaphore.acquire();
            //将最终结果返回
            return resultBuilder.toString();
        } catch (Exception e) {
            log.error("调用讯飞接口出现问题：{}", e.getMessage());
            return "调用大模型接口失败，请稍后尝试";
        }
    }

    public SparkDeskClient getSparkDeskClient() {
        WxModelConfigVo config = getConfig();
        SparkModelEnum sparkModelEnum = SparkModelEnum.getByType(config.getModelType());
        if (sparkModelEnum == null) {
            throw new ServiceException("无法匹配对应模型，请检查讯飞星火模型配置");
        }
        return SparkDeskClient.builder()
            .host(sparkModelEnum.getHost())
            .appid(config.getAppid())
            .apiKey(config.getApiKey())
            .apiSecret(config.getSecretKey())
            .build();
    }

    public AIChatRequest getAIChatRequestBase() {
        WxModelConfigVo config = getConfig();
        SparkModelEnum sparkModelEnum = SparkModelEnum.getByType(config.getModelType());
        if (sparkModelEnum == null) {
            throw new ServiceException("无法匹配对应模型，请检查讯飞星火模型配置");
        }
        //构建请求参数
        InHeader header = InHeader.builder()
            .uid(UUID.randomUUID().toString().substring(0, 10))
            .appid(config.getAppid()).build();
        Parameter parameter = Parameter.builder()
            .chat(Chat.builder()
                .domain(sparkModelEnum.getDomain())
                .maxTokens((config.getMaxTokens() != null && config.getMaxTokens() > 0) ? config.getMaxTokens() : 2048)
                .temperature(0.5)
                .build()).build();
        return AIChatRequest.builder().header(header).parameter(parameter).build();
    }

    public InPayload buildPayload(List<WxChatVo> chatVoList) {
        List<Text> text = new ArrayList<>();
        for (WxChatVo wxChatVo : chatVoList) {
            text.add(Text.builder()
                .role(wxChatVo.getRole())
                .content(wxChatVo.getContent())
                .build()
            );
        }
        InPayload payload = InPayload.builder().message(Message.builder().text(text).build()).build();
        return payload;
    }
}
